Subject:     [Source code] Quicktime movie and Quickdraw 3D model object for WAS
Date:        05/09  10:36 PM
Received:    05/09  10:49 PM
From:        Xiaolin Zhao, xlz@Chem.LSA.umich.edu
Reply-To:    WASTE Mailing List, waste@rhino16.fas.harvard.edu
To:          WASTE Mailing List, waste@rhino16.fas.harvard.edu

Hi, Everyone, 

	I put out these object handler code for your discussion and
improvement following our WASTE tradition. They are working now in my
Unicorn Editor v1.2.1. I would thank for any comments and suggestions. 

	Regards,

	Allen Zhao

// UCEDMovieQT.h

#ifdef __cplusplus
extern "C" {
#endif

#include <Movies.h>

typedef struct MovieFaceRec {
	PicHandle 		thePicture;
	Rect			theFrame;
} MovieFaceRec, *MovieFacePtr, **MovieFaceHdl;

OSErr	InstallMovieObject( WEReference theWE );
pascal OSErr	HandleNewMovie(Point *defaultObjectSize,WEObjectReference
objectRef);
pascal OSErr	HandleDisposeMovie(WEObjectReference objectRef );
pascal OSErr	HandleDrawMovie (Rect *destRect, WEObjectReference
objectRef );
pascal Boolean	HandleClickMovie(	Point hitPt, short modifiers, long
clickTime, WEObjectReference objectRef);
Boolean HandleMovieEvent(EventRecord *theEvent, WindowPtr window, Movie
theMovie);

#ifdef __cplusplus
}
#endif

// MooV Object Handler for the WASTE Text Engine
// by Xiaolin Zhao

#ifndef _WASTE_
#include "WASTE.h"
#endif

#include "UCEDMovieQT.h"

#ifndef _WASTEOBJECTS_
#include "WASTE_Objects.h"
#endif

#include "UCEDGlobals.h"
#include "UCEDAppleEvents.h"
#include "UCEDMiscUtil.h"

#define		kMovieIconID		300

// MovieFileType
//
// InstallMooVObject()
//		Installs the MooV handler into WASTE.
//
OSErr	InstallMovieObject( WEReference theWE )
{
OSErr	iErr;

#ifdef __cplusplus
	static WENewObjectUPP			newMooVUPP =
NewWENewObjectProc(HandleNewMovie);
	static WEDisposeObjectUPP		disposeMooVUPP =
NewWEDisposeObjectProc(HandleDisposeMovie);
	static WEDrawObjectUPP			drawMooVUPP =
NewWEDrawObjectProc(HandleDrawMovie);
	static WEClickObjectUPP         clickMooVUPP =
NewWEClickObjectProc(HandleClickMovie);
#else
	static WENewObjectUPP			newMooVUPP = NULL;
	static WEDisposeObjectUPP		disposeMooVUPP = NULL;
	static WEDrawObjectUPP			drawMooVUPP = NULL;
	static WEClickObjectUPP         clickMooVUPP = NULL;

	if ( newMooVUPP == NULL )
		newMooVUPP = NewWENewObjectProc(HandleNewMovie);
	if ( disposeMooVUPP == NULL )
		disposeMooVUPP =
NewWEDisposeObjectProc(HandleDisposeMovie);
	if ( drawMooVUPP == NULL )
		drawMooVUPP = NewWEDrawObjectProc(HandleDrawMovie);
	if ( clickMooVUPP == NULL )
		clickMooVUPP = NewWEClickObjectProc(HandleClickMovie);
#endif

	if ( newMooVUPP != NULL )
		iErr = WEInstallObjectHandler(MovieFileType, weNewHandler,
(UniversalProcPtr)newMooVUPP, theWE);
	else
		iErr = weUnknownObjectTypeErr;
	if (iErr) return(iErr);
	
	if ( disposeMooVUPP != NULL )
		iErr = WEInstallObjectHandler(MovieFileType,
weDisposeHandler, (UniversalProcPtr)disposeMooVUPP, theWE);
	else
		iErr = weUnknownObjectTypeErr;
	if (iErr) return(iErr);
	
	if ( drawMooVUPP != NULL )
		iErr = WEInstallObjectHandler(MovieFileType,
weDrawHandler, (UniversalProcPtr)drawMooVUPP, theWE);
	else
		iErr = weUnknownObjectTypeErr;
	if (iErr) return(iErr);
	
	if ( clickMooVUPP != NULL )
		iErr = WEInstallObjectHandler(MovieFileType,
weClickHandler, (UniversalProcPtr)clickMooVUPP, theWE);
	else
		iErr = weUnknownObjectTypeErr;
	if (iErr) return(iErr);
	return(noErr);
}

//
// New Object Handler for MooV
//
pascal OSErr	HandleNewMovie(Point *defaultObjectSize,WEObjectReference
objectRef)
{
Handle		theMovieHandle = WEGetObjectDataHandle(objectRef);
Movie		theMovie;
MovieController		thePlayer;
Rect		movieBounds;
OSErr		err = noErr;
MovieFaceHdl	theFace;
	err = MyNewHandle (sizeof(MovieFaceRec), &theFace);
	if (err != noErr) return err;

	err = NewMovieFromHandle (&theMovie, theMovieHandle, 

newMovieDontResolveDataRefs|newMovieDontAskUnresolvedDataRefs|newMovieDontAutoAlternates,
nil);
	if (err == noErr) {
		GetMovieBox(theMovie, &movieBounds);
		OffsetRect(&movieBounds, -movieBounds.left,
-movieBounds.top);
		SetMovieBox(theMovie, &movieBounds);
		thePlayer = NewMovieController (theMovie, &movieBounds,
mcTopLeftMovie);
		MCGetControllerBoundsRect(thePlayer, &movieBounds);

		(*theFace)->thePicture = GetMoviePict (theMovie, 0);
		(*theFace)->theFrame = movieBounds;
		WESetObjectRefCon(objectRef, (long)theFace);

		DisposeMovieController (thePlayer);
		DisposeMovie(theMovie);
		if (movieBounds.right - movieBounds.left < 32) {
			movieBounds.left = 0;
			movieBounds.right = 32;
		}
		if (movieBounds.bottom - movieBounds.top < 32) {
			movieBounds.top = 0;
			movieBounds.bottom = 32;
		}
		*defaultObjectSize = botRight(movieBounds);
	}

	return(err);
}

//
// Dispose Object Handler for MooV
//
pascal OSErr	HandleDisposeMovie(WEObjectReference objectRef )
{
Handle		theMovieHandle = WEGetObjectDataHandle(objectRef);
OSErr		err = noErr;
MovieFaceHdl	theFace = (MovieFaceHdl) WEGetObjectRefCon(objectRef);

	if ((*theFace)->thePicture!=nil)
KillPicture((*theFace)->thePicture);
	MyDisposeHandle (theFace);
	if (theMovieHandle) {
		DisposeHandle((Handle)theMovieHandle);
	}

	return(MemError());
}
//
// Draw Object Handler for MooV
//
pascal OSErr	HandleDrawMovie (Rect *destRect, WEObjectReference
objectRef )
{
OSErr		err = noErr;
Rect		iconRect;
MovieFaceHdl	theFace = (MovieFaceHdl) WEGetObjectRefCon(objectRef);
	
	if ((*theFace)->thePicture) {
		DrawPicture((*theFace)->thePicture, destRect);
		SetRect (&(*theFace)->theFrame, destRect->left,
destRect->top, destRect->right, destRect->bottom);
		SetRect(&iconRect, destRect->left, destRect->top,
destRect->left+32, destRect->top+32);
		err = PlotIconID(&iconRect,atNone,ttNone,kMovieIconID);
	}

	return( err );
}

pascal Boolean	HandleClickMovie(	Point hitPt, short modifiers, long
clickTime, WEObjectReference objectRef)
{
#pragma unused ( hitPt, clickTime)
Handle		theMovieHandle = WEGetObjectDataHandle(objectRef);
Movie		theMovie;
MovieController		thePlayer;
Rect		movieBounds;
OSErr		err = noErr;
Rect		iconRect;
WEReference	we = WEGetObjectOwner(objectRef);
WindowRef	window;
Boolean 				done = false;
EventRecord theEvent;
MovieFaceHdl	theFace = (MovieFaceHdl) WEGetObjectRefCon(objectRef);

	if (modifiers & 0x0001)         // look for double-clicks
	{
		err = NewMovieFromHandle (&theMovie, theMovieHandle, 

newMovieDontResolveDataRefs|newMovieDontAskUnresolvedDataRefs|newMovieDontAutoAlternates,
nil);
		if (err == noErr) {
			WEGetInfo( weRefCon, &window, we );
			// Now recall the destRect
			SetRect(&movieBounds, (*theFace)->theFrame.left,
(*theFace)->theFrame.top, 

(*theFace)->theFrame.right, (*theFace)->theFrame.bottom);
			SetMovieBox(theMovie, &movieBounds);

			SetMovieGWorld(theMovie, (CGrafPtr) window, 0);
			thePlayer = NewMovieController (theMovie,
&movieBounds, mcTopLeftMovie|mcWithFrame);
			if (thePlayer != nil) {
				err = MCDoAction (thePlayer,
mcActionSetKeysEnabled, (Ptr) true);
				StartMovie (theMovie);
				while (!done){
					WaitNextEvent (everyEvent,
&theEvent, 0, nil);
					if (( MCIsPlayerEvent(thePlayer,
&theEvent) == 0 )) {
						done =
HandleMovieEvent(&theEvent, window, theMovie);
					}
				}
				DisposeMovieController (thePlayer);
			}
			else { // this part is ok
				StartMovie (theMovie);
				while (!IsMovieDone(theMovie) && !done) {
					if (WaitNextEvent (everyEvent,
&theEvent, 0, nil)) {
						done =
HandleMovieEvent(&theEvent, window, theMovie);
					}
					MoviesTask (theMovie,
DoTheRightThing);
				}
			}
			// finish it up.
			// draw an icon for movie
			if ((*theFace)->thePicture != 0) {
				TimeRecord temp;
				KillPicture((*theFace)->thePicture);
				(*theFace)->thePicture = GetMoviePict
(theMovie, GetMovieTime(theMovie, &temp));
			}
			SetRect(&iconRect, movieBounds.left,
movieBounds.top, movieBounds.left+32, movieBounds.top+32);
			err =
PlotIconID(&iconRect,atNone,ttNone,kMovieIconID);
			DisposeMovie(theMovie);
		}
	}	

	WEUpdate(NULL, we);
	return( err );

}

Boolean HandleMovieEvent(EventRecord *theEvent, WindowPtr window, Movie
theMovie)
{
	WindowPtr 				whichWindow;
	switch ( theEvent->what ) 
	{
		case updateEvt:	
			whichWindow = (WindowPtr)theEvent->message;
			if (whichWindow == window) 
			{
				BeginUpdate (whichWindow);
				UpdateMovie(theMovie);
				SetPort (whichWindow);
				EraseRect (&whichWindow->portRect);
				EndUpdate (whichWindow);
			}
			break;
	
		case mouseDown:	
			return true;
			break;
	}
	return false;
}

// UCEDQuickDraw3D.h

#if GENERATINGPOWERPC

#include	<QD3DViewer.h>

typedef struct ModelFaceRec {
	PicHandle 		thePicture;
	Rect			theFrame;
} ModelFaceRec, *ModelFacePtr, **ModelFaceHdl;

void 	Init3DMF(void);
OSErr	InstallModelObject( WEReference theWE );
pascal OSErr	HandleNewModel(Point *defaultObjectSize,WEObjectReference
objectRef);
pascal OSErr	HandleDisposeModel(WEObjectReference objectRef );
pascal OSErr	HandleDrawModel (Rect *destRect, WEObjectReference
objectRef );
pascal Boolean	HandleClickModel(	Point hitPt, short modifiers, long
clickTime, WEObjectReference objectRef);
Boolean HandleModelEvent(EventRecord *theEvent, WindowRef window,
TQ3ViewerObject theViewer, Point size);

#ifdef __cplusplus
}
#endif

#endif  // PPC generation only.

// 3DMF Object Handler for the WASTE Text Engine
// by Xiaolin Zhao
#if GENERATINGPOWERPC

#ifndef _WASTE_
#include "WASTE.h"
#endif

#include "UCEDQuickDraw3D.h"

#ifndef _WASTEOBJECTS_
#include "WASTE_Objects.h"
#endif

#include "UCEDGlobals.h"
#include "UCEDMiscUtil.h"

#define		kModelIconID		400
#define		kModelWidth			200
#define		kModelHeight		240

//
--------------------------------------------------------------------------------------------------------------
void Init3DMF(void)
{
	long				result;
	
	if ((Gestalt(gestaltQD3D, &result) == noErr) &&
(Gestalt(gestaltSysArchitecture, &result) == noErr) && (result == 2)) {
		CFragConnectionID	connID;
		Ptr 				mainAddr;
		Str255				errName;
		
		if (GetSharedLibrary("\pQD3DViewerLib", 'pwpc', 1,
&connID, &mainAddr, errName) == noErr) {
			gMachineInfo.haveThreeD = true;
		}
	}
} // Init3DMF

// kType3DModel
//
// Install3DMFObject()
//		Installs the 3DMF handler into WASTE.
//
OSErr	InstallModelObject( WEReference theWE )
{
OSErr	iErr;

#ifdef __cplusplus
	static WENewObjectUPP			new3DMFUPP =
NewWENewObjectProc(HandleNewModel);
	static WEDisposeObjectUPP		dispose3DMFUPP =
NewWEDisposeObjectProc(HandleDisposeModel);
	static WEDrawObjectUPP			draw3DMFUPP =
NewWEDrawObjectProc(HandleDrawModel);
	static WEClickObjectUPP         click3DMFUPP =
NewWEClickObjectProc(HandleClickModel);
#else
	static WENewObjectUPP			new3DMFUPP = NULL;
	static WEDisposeObjectUPP		dispose3DMFUPP = NULL;
	static WEDrawObjectUPP			draw3DMFUPP = NULL;
	static WEClickObjectUPP         click3DMFUPP = NULL;

	if ( new3DMFUPP == NULL )
		new3DMFUPP = NewWENewObjectProc(HandleNewModel);
	if ( dispose3DMFUPP == NULL )
		dispose3DMFUPP =
NewWEDisposeObjectProc(HandleDisposeModel);
	if ( draw3DMFUPP == NULL )
		draw3DMFUPP = NewWEDrawObjectProc(HandleDrawModel);
	if ( click3DMFUPP == NULL )
		click3DMFUPP = NewWEClickObjectProc(HandleClickModel);
#endif

	if ( new3DMFUPP != NULL )
		iErr = WEInstallObjectHandler(kType3DModel, weNewHandler,
(UniversalProcPtr)new3DMFUPP, theWE);
	else
		iErr = weUnknownObjectTypeErr;
	if (iErr) return(iErr);
	
	if ( dispose3DMFUPP != NULL )
		iErr = WEInstallObjectHandler(kType3DModel,
weDisposeHandler, (UniversalProcPtr)dispose3DMFUPP, theWE);
	else
		iErr = weUnknownObjectTypeErr;
	if (iErr) return(iErr);
	
	if ( draw3DMFUPP != NULL )
		iErr = WEInstallObjectHandler(kType3DModel, weDrawHandler,
(UniversalProcPtr)draw3DMFUPP, theWE);
	else
		iErr = weUnknownObjectTypeErr;
	if (iErr) return(iErr);
	
	if ( click3DMFUPP != NULL )
		iErr = WEInstallObjectHandler(kType3DModel,
weClickHandler, (UniversalProcPtr)click3DMFUPP, theWE);
	else
		iErr = weUnknownObjectTypeErr;
	if (iErr) return(iErr);
	return(noErr);
}

//
// New Object Handler for 3DMF
//
pascal OSErr	HandleNewModel(Point *defaultObjectSize,WEObjectReference
objectRef)
{
OSErr		err = noErr;
Handle		theModelHandle = WEGetObjectDataHandle(objectRef);
WEReference	we = WEGetObjectOwner(objectRef);
Rect		modelBounds;
TQ3ViewerObject theViewer;	
unsigned long	validSize = GetHandleSize(theModelHandle);
WindowRef			pWindow;
ModelFaceHdl	theFace;
	err = MyNewHandle (sizeof(ModelFaceRec), &theFace);
	if (err != noErr) return err;


	err= WEGetInfo( weRefCon, &pWindow, we );

	SetRect(&modelBounds, 0, 0, kModelWidth, kModelHeight);

	theViewer = Q3ViewerNew((CGrafPtr)pWindow,  &modelBounds,  

kQ3ViewerDefault|kQ3ViewerButtonZoom|kQ3ViewerDrawFrame|kQ3ViewerButtonZoom); 

	if (theViewer != 0 && err==noErr) {
		if (Q3ViewerUseData(theViewer, *theModelHandle,
MyGetHandleSize(theModelHandle)) == noErr) {
			Q3ViewerGetBounds (theViewer, &modelBounds);
			OffsetRect(&modelBounds, -modelBounds.left,
-modelBounds.top);
			if (modelBounds.right - modelBounds.left < 32) {
				modelBounds.left = 0;
				modelBounds.right = 32;
			}
			if (modelBounds.bottom - modelBounds.top < 32) {
				modelBounds.top = 0;
				modelBounds.bottom = 32;
			}
			*defaultObjectSize = botRight(modelBounds);
		}
		// now save the ref to the object:
		(*theFace)->thePicture = Q3ViewerGetPict(theViewer);
		(*theFace)->theFrame = modelBounds;
		WESetObjectRefCon(objectRef, (long)theFace);
	}
	
	err = Q3ViewerDispose(theViewer);
	
	return(err);
}

//
// Dispose Object Handler for 3DMF
//
pascal OSErr	HandleDisposeModel(WEObjectReference objectRef )
{
OSErr		err = noErr;
Handle		theModelHandle = WEGetObjectDataHandle(objectRef);
ModelFaceHdl	theFace = (ModelFaceHdl) WEGetObjectRefCon(objectRef);

	if ((*theFace)->thePicture!=nil)
KillPicture((*theFace)->thePicture);
	MyDisposeHandle (theFace);

	if (theModelHandle) {
		DisposeHandle((Handle)theModelHandle);
	}

	return(err);
}
//
// Draw Object Handler for 3DMF
//
pascal OSErr	HandleDrawModel (Rect *destRect, WEObjectReference
objectRef )
{
OSErr		err = noErr;
Rect		iconRect;
ModelFaceHdl	theFace = (ModelFaceHdl) WEGetObjectRefCon(objectRef);

	if ((*theFace)->thePicture) {
		DrawPicture((*theFace)->thePicture, destRect);
		SetRect (&(*theFace)->theFrame, destRect->left,
destRect->top, destRect->right, destRect->bottom);
		// draw an icon for model
		SetRect(&iconRect, destRect->left, destRect->top,
destRect->left+32, destRect->top+32);
		err = PlotIconID(&iconRect,atNone,ttNone,kModelIconID);
	}
	return( err );
}

pascal Boolean	HandleClickModel(	Point hitPt, short modifiers, long
clickTime, WEObjectReference objectRef)
{
#pragma unused ( hitPt, clickTime)
Handle		theModelHandle = WEGetObjectDataHandle(objectRef);
OSErr		err = noErr;
WEReference	we = WEGetObjectOwner(objectRef);
TQ3ViewerObject theViewer;	
WindowRef	window;
Boolean 	done = false;
Rect		iconRect;
Rect		modelBounds;
EventRecord theEvent;
long		selStart, selEnd;
ModelFaceHdl	theFace = (ModelFaceHdl) WEGetObjectRefCon(objectRef);

	if (modifiers & 0x0001)         // look for double-clicks
	{
		err=WEGetInfo( weRefCon, &window, we );
		SetRect(&modelBounds, 0, 0, kModelWidth, kModelHeight);

		theViewer = Q3ViewerNew((CGrafPtr)window,  &modelBounds,  

kQ3ViewerDefault|kQ3ViewerButtonZoom|kQ3ViewerDrawFrame|kQ3ViewerButtonZoom); 

		if (theViewer != 0 && err==noErr) {
			Q3ViewerGetBounds (theViewer, &modelBounds);
			OffsetRect(&modelBounds, -modelBounds.left,
-modelBounds.top);
			OffsetRect(&modelBounds,
(*theFace)->theFrame.left, (*theFace)->theFrame.top);
			Q3ViewerSetBounds (theViewer, &modelBounds);
			if (Q3ViewerUseData(theViewer, *theModelHandle,
MyGetHandleSize(theModelHandle)) == noErr) {
				err = Q3ViewerDraw(theViewer);
				while (!done){
					if (WaitNextEvent (everyEvent,
&theEvent, 0, nil)) {
						done =
HandleModelEvent(&theEvent, window, theViewer,
WEGetObjectSize(objectRef));
					}
				}
				// finish it up.
				WEGetSelection(&selStart, &selEnd, we);
				WESetSelection(selEnd, selEnd, we);
				// draw an icon for model
				Q3ViewerGetBounds (theViewer,
&modelBounds);
				if ((*theFace)->thePicture != nil) {

KillPicture((*theFace)->thePicture);
					(*theFace)->thePicture =
Q3ViewerGetPict(theViewer);
				}
				err = Q3ViewerDispose(theViewer);
			}
		}
		SetRect(&iconRect, modelBounds.left, modelBounds.top,
modelBounds.left+32, modelBounds.top+32);
		err = PlotIconID(&iconRect,atNone,ttNone,kModelIconID);
	}

	WEUpdate(NULL, we);
	return( err );
}


Boolean HandleModelEvent(EventRecord *theEvent, WindowRef window,
TQ3ViewerObject theViewer, Point size)
{ 
	WindowPtr myWind; 
	OSErr theErr; 
	Rect modelBounds; 

	switch (theEvent->what) { 
		case updateEvt: 
			myWind = (WindowPtr)theEvent->message; 
			if (myWind==window) {
				BeginUpdate(window); 
				theErr = Q3ViewerDraw(theViewer); 
				EndUpdate(window); 
			}	
			break;
				
		case mouseDown:
			Q3ViewerGetBounds (theViewer, &modelBounds);
			SetRect(&modelBounds, modelBounds.left,
modelBounds.top, modelBounds.right, modelBounds.top + size.v);
			GlobalToLocal(&theEvent->where);
			if (PtInRect(theEvent->where, &modelBounds)) {
				LocalToGlobal(&theEvent->where);
				Q3ViewerEvent(theViewer, theEvent);
			}
			else {
				return true;
			}
			break; 
	} 
	return false;
}

#endif // PPC generation only.


// the following are I/O function for making a handle
OSErr Read3DMFFile(const FSSpec *pFileSpec, WEReference we)
{
	short 				fRefNum;
	OSErr				err = noErr;
	Handle	 			publicViewer = nil;
	Point				zeroPoint={0, 0};
	long 		validSize = 0;
	
	err = FSpOpenDF(pFileSpec, fsCurPerm, &fRefNum);
	if ( err != noErr )
		goto cleanup;
	err = GetEOF( fRefNum, &validSize );
	if ( err != noErr )
		goto cleanup;
	err = SetFPos( fRefNum, fsFromStart, 0L );
	if ( err != noErr )
		goto cleanup;

	//	Try to allocate a handle that large
	
	err = MyNewHandle( validSize, &publicViewer );
	if ( err != noErr ) {
		goto cleanup;
	}
	
	HLock( publicViewer );
	err = FSRead( fRefNum, &validSize, *publicViewer );
	HUnlock( publicViewer );
	if ( err != noErr )
		goto cleanup;
	
	err = FSClose( fRefNum );
	if ( err != noErr )
		goto cleanup;

	// insert the handle into the we
	err = WEInsertObject('3DMF', (Handle) publicViewer, zeroPoint,
we);

	// display an alert box if anything went wrong
	if (err != noErr) {
		ForgetHandle(&publicViewer);
		ErrorAlert( err );
	}
	
	return noErr;

cleanup:

	ForgetHandle(&publicViewer);

	if ( fRefNum > 0 ) {
		FSClose(fRefNum);
		fRefNum = 0;
	}
	
	return noErr;
}

OSErr	ReadMovieFile( const FSSpec *pFileSpec, WEReference we )
{	
	OSErr			err = noErr;
	short			fRefNum = 0;		
	Movie			theMovie;
	short			actualResId = 0;
	Handle	 		publicMovie;
	Point			zeroPoint={0, 0};

	err = OpenMovieFile(pFileSpec, &fRefNum, 0);
	if (err == noErr) {
		err  = NewMovieFromFile(&theMovie, fRefNum, &actualResId,
(unsigned char *) 0, newMovieActive, (Boolean *) 0);
		if ( err == noErr)
		{
			CloseMovieFile(fRefNum);
			if( GetMoviesError() == noErr) {
				if (MyNewHandle(0, &publicMovie) == noErr)
{
					err = PutMovieIntoHandle
(theMovie, publicMovie);
					if (!err) {
						err =
WEInsertObject('MooV', (Handle) publicMovie, zeroPoint, we);
					}
				}
			}
			DisposeMovie(theMovie);
		}
	}
	

cleanup:

	// display an alert box if anything went wrong
	if (err != noErr) {
		ErrorAlert( err );
	}

	return noErr;
}

// It is your job to examine if QT and 3D is there and install the handler
accordingly.

// As to the icon I put together the object image, it is only a badge
replace
// I don't like the badge provided by QT and 3D, and also it requires the
movie and model
// always in memory. I would rather just keep an image of them in memory.
// To see what kind of icon I put for QT and 3D, check out my shareware
Unicorn Editor
// <URL:http://www.concentric.net/~tsunmei/> for the latest version of
Unicorn Editor v1.2.1.

// remember that I created a "face" - PicHandle for each above object. 
// Before you delete the WEHandle, you have to explicitly dispose this 
// PicHandle and whatever in the Object RefCon. 
// These should be something like:

void DisposeWEandOBJ(WEReference we)
{
	WEObjectReference	objectRef;
	long	offset;
	OSErr	myErr = noErr;
	// 	find the embedded movie and model and destroy the face
record.
	// 	find the first object 
	offset = WEFindNextObject(-1, &objectRef, we);

	// repeat until all the objects are examined 
	while ((myErr == noErr) && (offset > -1) && (objectRef != nil)) { 
		// if it's a movie or model--kill its face 
		if (WEGetObjectType(objectRef)=='MooV') { 
			MovieFaceHdl		theFace = (MovieFaceHdl)
WEGetObjectRefCon(objectRef);
			KillPicture((*theFace)->thePicture);
			ForgetHandle((Handle*)&theFace);
		}
#if GENERATINGPOWERPC
		if (WEGetObjectType(objectRef)=='3DMF') { 
			ModelFaceHdl		theFace = (ModelFaceHdl)
WEGetObjectRefCon(objectRef);
			KillPicture((*theFace)->thePicture);
			ForgetHandle((Handle*)&theFace);
		}
#endif
		// get the next pict 
		offset = WEFindNextObject(offset, &objectRef, we);
	}
	
	//	destroy the WE record
	WEDispose( we );
}

// I release these codes, following the spirit of WASTE started with
Marco, 
// Dan, Tim, John and many others. I hope these codes can be debugged,
// improved and beneficial to everyone by the way of discussion.

// The object idea is great. As I see it, it really extends WASTE
functionality
// for example, what about a table object? a popup menu? etc. The problem
to be
// solved in case of table object is the size change involved in such
object. 
// The cell size of a table may change, and therefore the size of the
whole object. 
// I wish that someone think about it, and work together for such an
enhancement.




